#pragma once

#include <iostream>
#include <pthread.h>
#include <functional>
#include <memory>
#include "Sock.hpp"

static const uint16_t defaultport = 8888;

using func_t = std::function<std::string(std::string&)>;

class HttpServer;
class ThreadData
{
public:
    ThreadData(int sock, const std::string& ip, const uint16_t& port, HttpServer* hsvrp)
        :_sock(sock), _ip(ip), _port(port), _hsvrp(hsvrp)
    {}
    ~ThreadData()
    {}
public:
    int _sock;
    std::string _ip;
    uint16_t _port;
    HttpServer* _hsvrp;
};



class HttpServer
{
public:
    HttpServer(func_t f, uint16_t port = defaultport)
        : func(f), port_(port)
    {
    }

    void InitServer()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        logMessage(Debug, "InitServer success");
    }

    void HandlerHttpRequest(int sock)
    {
        // 通过套接字从客户端接收数据，认为一次就将序列化数据读完整了，只读一次
        char buffer[4096];
        std::string request;
        ssize_t s = recv(sock, buffer, sizeof(buffer)-1, 0);
        if(s > 0)
        {
            buffer[s] = 0;
            request = buffer;
            // 回调函数func在上层处理数据（业务处理），处理完后回来向客户端发送数据
            std::string response = func(request);
            send(sock, response.c_str(), response.size(), 0);
        }
        else
        {
            logMessage(Info, "client quit...");
        }
    }

    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        // 处理数据
        td->_hsvrp->HandlerHttpRequest(td->_sock);
        close(td->_sock);
        delete td;
        return nullptr;
    }

    void Start()
    {
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            // 接收响应，多线程处理数据
            int sock = listensock_.Accept(&clientip, &clientport);
            if (sock < 0)
            {
                continue;
            }
            logMessage(Debug, "Accept client success");

            pthread_t tid;
            ThreadData* td = new ThreadData(sock, clientip, clientport, this);
            pthread_create(&tid, nullptr, threadRoutine, td);
        }
    }
    ~HttpServer()
    {
    }

private:
    uint16_t port_;
    Sock listensock_;
    func_t func;
};